package com.fin.zw.aiqas.service;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.fin.zw.aiqas.entity.*;
import com.fin.zw.aiqas.enums.FormulaType;
import com.fin.zw.aiqas.enums.Status;
import com.fin.zw.aiqas.model.component.JsonDataModel;
import com.fin.zw.aiqas.model.request.SimulatorRequest;
import com.fin.zw.aiqas.repository.ConverseRepository;
import com.fin.zw.aiqas.repository.ConverseRuleRepository;
import com.fin.zw.aiqas.repository.RuleInfoRepository;
import com.fin.zw.aiqas.repository.UploadFileRepository;
import com.fin.zw.aiqas.util.AudioUtil;
import com.fin.zw.aiqas.util.FormulaUtil;
import com.google.common.collect.Sets;
import com.querydsl.core.BooleanBuilder;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.ListUtils;
import org.thymeleaf.util.SetUtils;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

@Service("simulatorService")
public class SimulatorService {

    private final static Logger log = LoggerFactory.getLogger(SimulatorService.class);

    @Value("${speech.recognition.service}")
    private String speechRecognitionServer;

    @Value("${file.dir}")
    private String fileDir;

    @Autowired
    private UploadFileRepository uploadFileRepository;

    @Autowired
    private ConverseRepository converseRepository;

    @Autowired
    private ConverseRuleRepository converseRuleRepository;

    @Autowired
    private RuleInfoRepository ruleInfoRepository;

    @Autowired
    private FileTransService fileTransService;

    @Autowired
    private CalculationResultService calculationResultService;


    /**
     * 模拟器质检语音
     *
     * @param request
     */
    public void simulatorDetection(SimulatorRequest request) {
        String result = new String();
        String path = new String();
        if (StringUtils.isNotBlank(request.getJsonData())) { //json内容
            result = request.getJsonData();
        } else { //文件
            UploadFile uploadFile = uploadFileRepository.findById(request.getFileId()).get();
            String url = fileDir + File.separator + uploadFile.getFileName();
            path = url;
            if ("aliyun".equals(speechRecognitionServer)) {
                String resultJson = fileTransService.speechRecognition(url);
                result = fileTransService.formatResult(resultJson);
            } else if ("xunfei".equals(speechRecognitionServer)) {
                result = AudioUtil.audioToText(url);
            }
        }
        List<Converse> converses = convertToList(result, path);
        //文件内容信息处理
        List<Converse> converseList = converseRepository.saveAll(converses);

        List<ConverseRule> converseRuleList = saveConverseRule(request.getSceId(), converseList);
        if (!ListUtils.isEmpty(converseRuleList)) {
            converseRuleRepository.saveAll(converseRuleList);
        }
    }

    /**
     * 获取文本内容并命中规则信息
     *
     * @param jsonData 调用文件解析后的json
     * @return
     */
    public List<Converse> convertToList(String jsonData, String path) {
        //质检并解析语音识别语句
        List<Converse> converseList = new ArrayList<>();
        List<JsonDataModel> converses = JSONObject.parseArray(jsonData, JsonDataModel.class);
        if (CollectionUtil.isEmpty(converses))
            return converseList;
        for (JsonDataModel model : converses) {
            Converse converse = new Converse();
            if (StringUtils.isNotBlank(path)) {
                converse.setFilePath(path);
                File file = new File(path);
                converse.setFileName(file.getName());
            }
            converse.setBg(Long.valueOf(model.getBg()));
            converse.setEd(Long.valueOf(model.getEd()));
            converse.setStartTime(new Date());
            converse.setEndTime(new Date());
            converse.setSortNum(converses.indexOf(model));
            converse.setContent(model.getOnebest());
            converse.setSpeaker(model.getSpeaker());
            converseList.add(converse);
        }
        return converseList;
    }

    /**
     * 获取每句话对应的规则
     *
     * @param sceId
     * @param converseList
     * @return
     */
    public List<ConverseRule> saveConverseRule(Long sceId, List<Converse> converseList) {
        List<ConverseRule> resultList = new ArrayList<>();
        for (Converse converse : converseList) {
            Set<RuleInfo> ruleInfoSet = getCalculationRuleInfo(sceId, converse.getContent());
            if (!SetUtils.isEmpty(ruleInfoSet)) {
                ruleInfoSet.forEach(ruleInfo -> {
                    ConverseRule converseRule = new ConverseRule();
                    converseRule.setConverseId(converse.getId());
                    converseRule.setRuleInfo(ruleInfo);
                    resultList.add(converseRule);
                });
            }
        }
        return resultList;
    }

    /**
     * 获取文本满足的规则
     *
     * @param sceId
     * @param chatRecord
     * @return
     */
    public Set<RuleInfo> getCalculationRuleInfo(Long sceId, String chatRecord) {
        //存储满足条件的规则
        Set<RuleInfo> rules = new HashSet<>();
        if (sceId == null || StringUtils.isEmpty(chatRecord)) {
            return null;
        }
        BooleanBuilder builder = new BooleanBuilder();
        QRuleInfo qRuleInfo = QRuleInfo.ruleInfo;
        builder.and(qRuleInfo.scenesInfo.id.eq(sceId));
        builder.and(qRuleInfo.states.in(Status.START));
        Iterable<RuleInfo> iterable = ruleInfoRepository.findAll(builder);
        Set<RuleInfo> ruleSet = Sets.newHashSet(iterable);
        if (SetUtils.isEmpty(ruleSet)) return null;
        log.info("遍历所有的规则,获取对应的质检点信息");
        for (RuleInfo e : ruleSet) {
            //获取规则的关系表达式
            String relation = calculationResultService.relationController(e.getRelation());
            log.info("遍历质检点信息,获取质检点类型并进行操作");
            Set<FormulaInfo> formulas = e.getFormulaInfos();
            log.info("存储质检点的命中结果,质检点的Id作为key值,命中为true,未命中为false;");
            Map<String, Integer> resultMap = new HashMap();
            //同步过得关键词
            List<FormulaInfo> keywords = formulas.stream().filter(t -> t.getFormulaType().equals(FormulaType.KEYWORD)).collect(Collectors.toList());
            for (FormulaInfo info : keywords) {
                log.info("判断关键字类型的质检点是否命中!!");
                resultMap.put(info.getId().toString(), calculationResultService.assertionKeyWords(info, chatRecord));
            }
            try {
                if (FormulaUtil.jsonToFormula(relation, resultMap) == 1) rules.add(e);
            } catch (RuntimeException exp) {
                log.error("规则表达式替换错误!");
                exp.printStackTrace();
            }
        }
        return rules;
    }
}
